//!
/************************************************************************************************************
 * @file RBRenderTargetGroup.cpp
 ************************************************************************************************************/

/************************************************************************************************************
 * Precompiled Header
 ************************************************************************************************************/
#include "RBMainPCH.h"
 
/************************************************************************************************************
 * Includes
 ************************************************************************************************************/

#include "RBRenderTargetGroup.h"
#include "RBRenderer.h"
#include "RBHardwareBufferManager.h"
#include "RBTexture.h"

#include "RBRenderProcess/RBRenderTargetView.h"
#include "RBRenderProcess/RBDepthStencilView.h"
#include "RBRenderProcess/RBShaderResourceView.h"

/************************************************************************************************************
 * Defines
 ************************************************************************************************************/

/************************************************************************************************************
 * Implementation
 ************************************************************************************************************/

/************************************************************************************************************
 * Constructor
 ************************************************************************************************************/
RBRenderTargetGroup::RBRenderTargetGroup(const std::vector<RBRenderTargetView*>& vBuffers, RBDepthStencilView* pDSBuffer, bool bOwnsData)
: m_bOwnsData(bOwnsData)
{
    m_aColorBuffers = vBuffers;
    m_pDSBuffer = pDSBuffer;
}

/************************************************************************************************************
 * Destructor
 ************************************************************************************************************/
RBRenderTargetGroup::~RBRenderTargetGroup()
{
    if (m_bOwnsData)
    {
        for (uint32 ui=0; ui < m_aColorBuffers.size(); ++ui)
        {
            delete m_aColorBuffers[ui];
        }

        delete m_pDSBuffer;
    }
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBRenderTargetView* RBRenderTargetGroup::GetRenderTargetView( uint32 uiBuffer ) const
{
    return m_aColorBuffers[uiBuffer];
}


/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBDepthStencilView* RBRenderTargetGroup::GetDepthStencilView() const
{
    return m_pDSBuffer;
}

static inline void AddViewsAndResources(RBTexture* pColorBuffer, std::vector<RBRenderTargetView*>& vBuffers, RBHardwareBufferManager* pHBMgr)
{
    vBuffers.push_back( (pColorBuffer != NULL) ? pHBMgr->CreateRenderTargetView(pColorBuffer, pColorBuffer->GetFormat()) : NULL);
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBRenderTargetGroup* RBRenderTargetGroup::Create(RBTexture* pColorBuffer, RBTexture* pDSBuffer, 
                                                 RBTexture* pColorBuffer1, RBTexture* pColorBuffer2, RBTexture* pColorBuffer3)
{
    std::vector<RBRenderTargetView*> vBuffers;

    RBHardwareBufferManager* pHBMgr = RBRenderer::GetSingleton()->GetHBMgr();

    AddViewsAndResources(pColorBuffer, vBuffers, pHBMgr);

    if (pColorBuffer1) { AddViewsAndResources(pColorBuffer1, vBuffers, pHBMgr); }
    if (pColorBuffer2) { AddViewsAndResources(pColorBuffer2, vBuffers, pHBMgr); }
    if (pColorBuffer3) { AddViewsAndResources(pColorBuffer3, vBuffers, pHBMgr); }

    RBDepthStencilView* pDSView = (pDSBuffer != NULL) ? pHBMgr->CreateDepthStencilView(pDSBuffer, pDSBuffer->GetFormat()) : NULL;

    RBRenderTargetGroup* pGroup = new RBRenderTargetGroup(vBuffers, pDSView, true);
    return pGroup;
}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
RBRenderTargetGroup* RBRenderTargetGroup::Create(uint32 uiWidth, uint32 uiHeight, RBPixelFormat eColorFormat, RBPixelFormat eDSFormat,
                                                 bool bColorIsTexture, bool bDSIsTexture, uint32 uiMipCount, uint32 uiMSAA, uint32 uiColorBufferCount)
{
    std::vector<RBRenderTargetView*> vBuffers;
    RBDepthStencilView* pDSView = NULL;

    RBHardwareBufferManager* pHBMgr = RBRenderer::GetSingleton()->GetHBMgr();

	if (eColorFormat != PF_UNKNOWN)
	{
		if (bColorIsTexture)
		{
			for (uint32 ui=0; ui < uiColorBufferCount; ++ui)
			{
				assert (uiMSAA == 0);
				// No MSAA: We can directly create a texture that we will render to
                RBTexture* pColorTexture = pHBMgr->CreateTexture(rb_hw_buffer_usage::HBU_GPUWRITE | 
                                                                 rb_hw_buffer_usage::HBU_RENDER_TARGET | 
                                                                 rb_hw_buffer_usage::HBU_SHADER_RESOURCE |
                                                                 rb_hw_buffer_usage::HBU_SHARED, 
                                                                 uiWidth, uiHeight, eColorFormat, RBTextureType::SURFACE, uiMipCount);
				vBuffers.push_back(pHBMgr->CreateRenderTargetView(pColorTexture, eColorFormat));
			}
		}
		else
		{
			// We simply want to create a RT: simply create them
			for (uint32 ui=0; ui < uiColorBufferCount; ++ui)
			{
                RBTexture* pColorBuffer = pHBMgr->CreateRenderTarget(rb_hw_buffer_usage::HBU_GPUWRITE | rb_hw_buffer_usage::HBU_RENDER_TARGET, uiWidth, uiHeight, eColorFormat, uiMSAA);
				vBuffers.push_back(pHBMgr->CreateRenderTargetView(pColorBuffer, eColorFormat));
			}
		}
	}

	if (eDSFormat != PF_UNKNOWN)
	{
		if (bDSIsTexture)
		{
			RBTexture* pDSTexture = pHBMgr->CreateTexture(rb_hw_buffer_usage::HBU_DEPTHSTENCIL, uiWidth, uiHeight, eDSFormat, RBTextureType::SURFACE, uiMipCount);
			if (uiMSAA != 0)
			{
				RBTexture* pDSBuffer = pHBMgr->CreateRenderTarget(rb_hw_buffer_usage::HBU_DEPTHSTENCIL, uiWidth, uiHeight, eDSFormat, uiMSAA);
                pDSView = pHBMgr->CreateDepthStencilView(pDSBuffer, pDSBuffer->GetFormat());
			}
			else
			{
                pDSView = pHBMgr->CreateDepthStencilView(pDSTexture, pDSTexture->GetFormat());
			}
		}
		else
		{
			RBTexture* pDSBuffer = RBRenderer::GetSingleton()->GetHBMgr()->CreateRenderTarget(rb_hw_buffer_usage::HBU_DEPTHSTENCIL, uiWidth, uiHeight, eDSFormat, uiMSAA);
            pDSView = pHBMgr->CreateDepthStencilView(pDSBuffer, pDSBuffer->GetFormat());
		}
	}

    RBRenderTargetGroup* pRTT = new RBRenderTargetGroup(vBuffers, pDSView, true);
    
    return pRTT;
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBRenderTargetGroup* RBRenderTargetGroup::Create( RBRenderTargetView* pColorView0 /*= 0*/, RBDepthStencilView* pDSView /*= 0*/, RBRenderTargetView* pColorView1 /*= 0*/, RBRenderTargetView* pColorView2 /*= 0*/, RBRenderTargetView* pColorView3 /*= 0*/ )
{
    std::vector<RBRenderTargetView*> vBuffers;
    std::vector<RBShaderResourceView*> vTextures;

    if (pColorView0) { vBuffers.push_back(pColorView0); }
    if (pColorView1) { vBuffers.push_back(pColorView1); }
    if (pColorView2) { vBuffers.push_back(pColorView2); }
    if (pColorView3) { vBuffers.push_back(pColorView3); }

    RBRenderTargetGroup* pGroup = new RBRenderTargetGroup(vBuffers, pDSView, false);
    return pGroup;
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
uint32 RBRenderTargetGroup::GetBufferCount()
{
    return m_aColorBuffers.size();
}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
void RBRenderTargetGroup::Resize(uint32 /*uiWidth*/, uint32 /*uiHeight*/)
{
/*
    for (uint32 ui=0; ui<m_aColorBuffers.size(); ++ui)
    {
        m_aColorBuffers[ui]->Resize(uiWidth, uiHeight);
        if (m_aColorTextures[ui])
        {
            m_aColorTextures[ui]->Resize(uiWidth, uiHeight);
        }
    }

    if (m_spDSBuffer)
    {
        m_spDSBuffer->Resize(uiWidth, uiHeight);
    }

    if (m_spDSTexture)
    {
        m_spDSTexture->Resize(uiWidth, uiHeight);
    }
*/
}

const RBRenderTargetView*const* RBRenderTargetGroup::GetRenderTargetViews() const
{
    return &m_aColorBuffers[0];
}


/************************************************************************************************************/
